package meatslope2.gameengine.helpers;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;

import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
import javax.microedition.khronos.opengles.GL11Ext;

import meatslope2.application.IGameContext;
import meatslope2.gameengine.gameobjects.model.Sprite;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLException;
import android.opengl.GLUtils;
import android.util.Log;

public final class BitmapLoader 
{
	// ===========================================================
	// Members
	// ===========================================================
	
    // Specifies the format our textures should be converted to upon load.
    private final BitmapFactory.Options sBitmapOptions = new BitmapFactory.Options();
    
    @SuppressLint("UseSparseArrays") //This is done before run-time and should not be an issue
	private final HashMap<Integer, Integer> textureMapper = new HashMap<Integer, Integer>();
    
	// ===========================================================
	// Cached Members
	// ===========================================================
	
    // Pre-allocated arrays to use at runtime so that allocation during the can be avoided.
    private final int[] textureNameWorkspace = new int[1];
    private final int[] cropWorkspace = new int[4];
    
    
	// ===========================================================
	// Methods
	// ===========================================================
    
    /**
     * Sets the texture name to the sprite
     */
    public final void loadBitmap(IGameContext gameContext, GL10 gl, Sprite sprite) 
    {
        if (gameContext == null || gl == null) 
        	return;
        
        //If we already have glTexParameteriv this resource, do not compute again
        final int resourceId = sprite.getResourceId();
        if(textureMapper.containsKey(resourceId))
        {
        	sprite.setTextureName(textureMapper.get(resourceId));
        	return;
        }
        
        gl.glGenTextures(1, textureNameWorkspace, 0);

        int textureName = textureNameWorkspace[0];
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);

        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
        gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

        gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE, GL10.GL_REPLACE);

        InputStream is = gameContext.openRawResource(resourceId);
        Bitmap bitmap;
        try 
        {
            bitmap = BitmapFactory.decodeStream(is, null, sBitmapOptions);
        } 
        finally 
        {
            try 
            {
                is.close();
            } 
            catch (IOException e) 
            {
                Log.i("BitmapLoader", "IOException decoding steam: " + e.getMessage());
            }
        }

        GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);

        cropWorkspace[0] = 0;
        cropWorkspace[1] = bitmap.getHeight();
        cropWorkspace[2] = bitmap.getWidth();
        cropWorkspace[3] = -bitmap.getHeight();
        
        bitmap.recycle();

        ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D, 
                GL11Ext.GL_TEXTURE_CROP_RECT_OES, cropWorkspace, 0);

        int error = gl.glGetError();
        if (error != GL10.GL_NO_ERROR)
            throw new GLException(error);
        else
        {
	        sprite.setTextureName(textureName);
	        
	        //Cache this in case another sprite with the same resourceId is passed again
	        textureMapper.put(resourceId, textureName);
        }
    }
}
